<script>
import {
  uploadSlice,
  createUploadTask,
  mergeSlices,
  getVideos,
  addContent,
  deleteVideo
} from '@/api/train'
import { atLeastN, last } from '@/utils/kris_utils'
import { mapActions, mapGetters } from 'vuex'
export default {
  data() {
    return {
      test: false,
      isCheckbox: false,
      loading: true,
      list: [],
      gapSize: 20, // px
      rowSize: 6,
      selected: [],
      container: {
        width: null,
        paddingLeft: null,
        paddingRight: null
      },
      videos: [],
      videoPlayer: {
        visible: false,
        title: '',
        path: ''
      },
      paging: {
        size: 10,
        current: 1,
        total: 0
      },
      isLoading: false,
      condition: {
        keyword: ''
      },
      uploadForm: {
        visible: false,
        form: {
          name: '',
          minViews: 1,
          file: null
        },
        formRules: {
          name: [
            {
              required: true,
              message: '视频名称不能为空',
              trigger: ['blur', 'change']
            },
            { min: 1, max: 10, message: '视频名称长度应在1-10之间', trigger: 'blur' }
          ],
          minViews: [
            {
              validator: (rule, value, callback) => {
                return value >= 0
                  ? callback()
                  : callback(new Error('最少播放次数不能小于0'))
              },
              required: true,
              trigger: ['blur', 'change']
            }
          ],
          file: [
            {
              validator: (rule, value, callback) => {
                return value instanceof File
                  ? callback()
                  : callback(new Error('请选择视频'))
              },
              required: true,
              trigger: ['blur', 'change']
            }
          ]
        }
      },
      uploadingOverview: {
        visible: false,
        tasks: [
          /**
           * taskID
           * state:await uploading failed success
           * localURL
           * url
           * progress:number
           * name
           */
        ]
      },
      debounceFns: {
        handleResize: null
        // handleResize: this.makeDebounceFn(this.handleWindowResize, 300)
      }
    }
  },
  computed: {
    ...mapGetters(['train']),
    videoListFormatted() {
      const { rowSize, videos: Videos } = this
      const videos = Videos
        .filter((item) => item.type === 'mp4')
      const rows = []
      const rowCount = Math.ceil(videos.length / rowSize)
      for (let i = 0, offset = 0; i < rowCount; i++, offset += rowSize) {
        rows.push(videos.slice(offset, offset + rowSize))
      }
      // const arr=rows.flat(1)
      // console.log(arr,'arr');
      return rows.flat(1)
    },
    videoSelected() {
      return this.videos.filter(item => item.checked)
    },
    availableWidth() {
      const { gapSize, rowSize, container } = this
      return (
        container.width -
        (container.paddingLeft + container.paddingRight) -
        gapSize * (rowSize - 1)
      )
    },
    itemWidth() {
      return this.availableWidth / this.rowSize
    }
  },
  methods: {
    ...mapActions('train', ['addTask', 'setTask', 'removeSuccessTask']),
    progressFormat(percentage) {
      return percentage === 100 ? '上传完成' : `${percentage}%`
    },
    getFileSuffix(file = new File()) {
      const fileName = file.name
      const arr = fileName.split('.')

      return last(arr) ?? ''
    },
    formatSeconds(seconds) {
      const h = Math.floor(seconds / 3600)
      const m = Math.floor((seconds % 3600) / 60)
      const s = seconds % 60
      return `${h < 10 ? '0' + h : h}:${m < 10 ? '0' + m : m}:${s < 10 ? '0' + s : s}`
    },
    durationFormatter(duration) {
      const Sec = 1
      const Min = Sec * 60
      const Hour = Min * 60

      const times = []

      const hour = Math.floor(duration / Hour)

      times.push(hour)
      if (hour > 0) {
        duration -= hour * Hour
      }

      const min = Math.floor(duration / Min)
      times.push(hour)
      if (min > 0) {
        duration -= min * Min
      }

      times.push(duration)
      return times
        .map((item) => {
          return item > 9 ? `${item}` : `0${item}`
        })
        .join(':')
    },
    handlePageChange(currentPage) {
      this.paging.current = currentPage
      this.initData()
    },
    handlePageSizeChange(size) {
      this.paging.size = size
      this.initData()
    },
    buildTaskClasses(state) {
      const m = {
        await: '',
        uploading: '',
        success: 'task-item--success',
        failed: 'task-item--failed'
      }
      return m[state]
    },
    buildProgressState(state) {
      const m = {
        await: null,
        uploading: null,
        success: 'success',
        failed: 'exception'
      }
      return m[state] ?? null
    },
    buildStatusChangeHandlers(taskID, form) {
      const findIndexByTaskId = () => {
        return this.train.videoUploadTasks.findIndex((task) => {
          return task.taskID === taskID
        })
      }

      const onStart = () => {
        const i = findIndexByTaskId()
        if (i === -1) return
        const task = {
          ...this.train.videoUploadTasks[i],
          state: 'uploading'
        }

        this.setTask({ index: i, task })
      }

      const onChange = (progress) => {
        const i = findIndexByTaskId()
        if (i === -1) return
        console.log(progress)
        const task = {
          ...this.train.videoUploadTasks[i],
          progress
        }
        this.setTask({ index: i, task })
      }

      const onFailed = (e) => {
        const i = findIndexByTaskId()
        if (i === -1) return
        const task = { ...this.train.videoUploadTasks[i], state: 'failed' }
        this.setTask({ index: i, task })
      }

      const onSuccess = (url) => {
        const i = findIndexByTaskId()
        if (i === -1) return

        const { minViews, name } = form

        const formdata = new FormData()
        formdata.append('path', url)
        formdata.append('name', name)
        formdata.append('mini_num', minViews)

        addContent(formdata)
          .then((res) => {
            if (res.code !== 200) {
              onFailed(new Error(res.message))
              return
            }

            const data = {
              ...this.train.videoUploadTasks[i],
              url,
              state: 'success',
              progress: 100
            }

            this.setTask({ index: i, task: data })
            this.$emit('refresh')

            setTimeout(() => {
              this.removeSuccessTask()
            }, 1000)
          })
          .catch((err) => {
            onFailed(err)
          })
      }

      return {
        onStart,
        onChange,
        onSuccess,
        onFailed
      }
    },
    buildMetadata(data) {
      const { file } = data
      const localURL = URL.createObjectURL(file)
      const taskId = last(localURL.split('/'))
      const handlers = this.buildStatusChangeHandlers(taskId, data)

      if (!taskId) {
        throw new Error('创建任务id失败')
      }

      return {
        localURL,
        taskId,
        handlers
      }
    },
    createUploadTask() {
      this.$refs.form?.validate((flag) => {
        if (!flag) return

        const metadata = this.buildMetadata({ ...this.uploadForm.form })
        this.addTask({
          taskID: metadata.taskId,
          state: 'await',
          localURL: metadata.localURL,
          url: null,
          progress: 0,
          name: this.uploadForm.form.name
        })
        this.uploadVideo(
          this.uploadForm.form.file,
          metadata,
          1024 * 1024 * 1,
          2
        )
        this.$refs.form?.resetFields()
        this.closeUploadForm()
        this.$message.success('上传任务添加成功 请在上传队列中查看')
      })
    },
    viewsInput(e) {
      const n = parseInt(e)
      this.uploadForm.form.minViews = n || 0
    },
    openVideoSelector() {
      this.$refs?.fileSelector?.dispatchEvent(new MouseEvent('click'))
    },
    onFileSelectorChange(e) {
      if (e.target.files.length <= 0) {
        return
      }

      const files = [...e.target.files]
      const firstFile = files[0]

      if (firstFile.size > 1024 * 1024 * 1024) {
        this.$message.error('视频不能大于1G 请重新选择')
        return
      }
      this.uploadForm.form.file = firstFile
      this.clearFileSelector()
    },
    clearFileSelector() {
      this.$refs.fileSelector.value = null
    },
    openPlayer(video) {
      const { name, path } = video
      this.videoPlayer = {
        title: name,
        path,
        visible: true
      }
    },
    handlePlayerDialogClose() {
      this.videoPlayer.visible = false
      this.$refs['video-player']?.pause?.()
      if (document.pictureInPictureElement) {
        document.exitPictureInPicture()
      }
    },
    showUploadingOverview() {
      this.uploadingOverview.visible = true
    },
    closeUploadingOverview() {
      this.uploadingOverview.visible = false
    },
    showUploadForm() {
      this.uploadForm.visible = true
    },
    closeUploadForm() {
      this.uploadForm.visible = false
    },
    async fetchVideos() {
      const { current, size } = this.paging

      const params = {
        paginate: size,
        page: current,
        type: 'mp4',
        name: this.condition.keyword
      }

      const result = await getVideos(params)
      console.log(result, '视频数据')
      if (result.code === 200) {
        this.loading = false
      }
      if (result.code !== 200) { throw new Error(result.message ?? '获取视频失败') }

      this.videos = result.data.data.map(item => {
        return {
          checked: false,
          ...item
        }
      })
      this.paging.total = result.data?.total ?? 0
    },
    async refresh() {
      this.paging = this.$options.data().paging
      this.initData()
    },
    async loadData() {
      await Promise.allSettled([this.fetchVideos()])
    },
    async initData() {
      this.isLoading = true
      await this.loadData()
      this.isLoading = false
    },
    handleWindowResize() {
      console.log('resize')
      if (!this.$refs.container) return
      const styles = getComputedStyle(this.$refs.container)
      this.container.paddingLeft = parseFloat(styles.paddingLeft)
      this.container.paddingRight = parseFloat(styles.paddingRight)
      this.container.width = this.$refs.container.offsetWidth
    },
    buildRowStyles(index) {
      if (index === 0) return {}
      return {
        marginTop: `${this.gapSize}px`
      }
    },
    buildItemStyles(index) {
      const { gapSize, availableWidth, itemWidth } = this
      return {
        marginLeft: index === 0 ? '0' : `${gapSize}px`,
        width: `${itemWidth}px`
      }
    },
    async uploadVideo(
      file = new File(),
      metadata,
      sliceSize = 1024 * 1024 * 2,
      concurrency = 5
    ) {
      try {
        const hooks = metadata.handlers
        const fileSuffix = this.getFileSuffix(file)
        const fileName = `${metadata.taskId}.${fileSuffix}`
        const taskID = await this.createTask(fileName)
        const slices = this.fileSplit(file, sliceSize)
        const sliceCount = Math.ceil(slices.length / concurrency)
        const sliceUploadResult = []
        const total = file.size
        let submitted = 0

        hooks?.onStart?.()
        for (
          let i = 0, offset = 0;
          i < sliceCount;
          i++, offset += concurrency
        ) {
          const tasks = slices
            .slice(offset, offset + concurrency)
            .map((slice, index) =>
              this.uploadSliceWithRetry({
                taskID,
                slice,
                index: i * concurrency + index + 1,
                sliceSize: slice.size,
                fileName: fileName
              }).then((result) => {
                submitted += slice.size
                hooks?.onChange?.(
                  parseFloat(((submitted / total) * 100).toFixed(1))
                )
                return result
              })
            )

          const result = await Promise.all(tasks)
          sliceUploadResult.push(...result)
        }

        const url = await this.mergeSlices({
          taskID,
          fileName: fileName,
          sliceResults: sliceUploadResult
        })

        hooks?.onSuccess?.(url)
      } catch (e) {
        hooks?.onFailed?.()
        console.log('失败了', e)
      }
    },
    uploadSliceWithRetry(slice, retryLimit = 3) {
      return new Promise(async(resolve, reject) => {
        let failCount = 0
        let failReason = null
        let isSuccess = false
        while (failCount < 3 && !isSuccess) {
          await this.uploadSlice(slice)
            .then((res) => {
              resolve(res)
              isSuccess = true
            })
            .catch((e) => {
              failCount++
              failReason = e
            })
        }
        !isSuccess && reject(failReason)
      })
    },
    fileSplit(file, sliceSize = 1024 * 1024 * 2) {
      if (!file) return []
      const fileSize = file.size
      const slices = []
      for (
        let c = 0, _sliceSize = 0, b = 0, e = 0;
        c < fileSize;
        c += _sliceSize, b = e
      ) {
        _sliceSize = Math.min(sliceSize, fileSize - c)
        e = b + _sliceSize
        slices.push(file.slice(b, e))
      }
      return slices
    },
    async createTask(filename) {
      const formdata = new FormData()
      formdata.append('filename', filename)

      const result = await createUploadTask(formdata)

      if (result.code !== 200) { throw new Error(result.message ?? '创建任务失败') }

      return result.data
    },
    async uploadSlice({ taskID, slice, index, sliceSize, fileName }) {
      const formdata = new FormData()
      formdata.append('id', taskID)
      formdata.append('file', slice)
      formdata.append('i', index)
      formdata.append('size', sliceSize)
      formdata.append('filename', fileName)

      const result = await uploadSlice(formdata)

      if (result.code !== 200) { throw new Error(result.message ?? '分片上传失败') }

      const { PartNumber, ETag } = result.data
      return {
        partNumber: parseInt(PartNumber),
        eTag: ETag.match('[0-9a-z]+')[0]
      }
    },
    async mergeSlices({ taskID, fileName, sliceResults }) {
      const formdata = new FormData()
      formdata.append('id', taskID)
      formdata.append('filename', fileName)
      formdata.append(
        'arr',
        JSON.stringify(
          sliceResults.map((item) => ({
            PartNumber: item.partNumber,
            ETag: item.eTag
          }))
        )
      )
      const result = await mergeSlices(formdata)
      if (result.code !== 200) { throw new Error(result.message ?? '合并分片失败') }

      return result.data.path
    },
    makeDebounceFn(fn, delay = 500) {
      let timer = null

      return function() {
        if (timer) {
          clearTimeout(timer)
        }
        timer = setTimeout(() => {
          fn.apply(this, arguments)
          timer = null
        }, delay)
      }
    },
    // 处理国际标准时间
    setBIHTime(data) {
      return data.substring(0, 10)
    },
    // 视频管理
    videoManagement() {
      this.$message.warning('注意，被选入课程的视频不可删除！')
      this.isCheckbox = true
    },
    // 删除视频
    async deleteSelectedVideo() {
      const arr = []
      this.videos.filter(item => item.checked === true).forEach(value => {
        arr.push(value.id)
      })
      try {
        const res = await deleteVideo({ study_id: JSON.stringify(arr) })
        if (Array.isArray(res.data)) {
          this.$message.error('删除失败所选视频已被绑定')
        } else {
          this.$message.success('删除成功')
          this.isCheckbox = false
        }
        this.initData()
        console.log(res.data)
      } catch (err) {
        console.log(err)
      }
    },
    // 全选视频
    selectAllVideo() {
      this.videos.forEach(item => {
        if (item.user_all <= 0) {
          item.checked = true
        }
      })
    },
    // 取消选择
    cancelOpt() {
      this.isCheckbox = false
      this.videos.forEach(item => {
        item.checked = false
      })
    },
    checkup() {
      this.videos.filter(item => item.checked === true).forEach(value => {
        this.selected.push(value.id)
      })
    },
    setVideoName(name) {
      if (name && name.length > 10) {
        return name.substring(0, 10) + '...'
      } else {
        return name
      }
    }
  },
  created() {
    this.debounceFns.handleResize = this.makeDebounceFn(this.handleWindowResize, 300)
    console.log(this)
    this.initData()
    this.$on('refresh', this.initData)
  },
  mounted() {
    this.handleWindowResize()
    window.addEventListener('resize', this.debounceFns.handleResize)
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.debounceFns.handleResize)
  }
}
</script>
<template>
  <div
    ref="container"
    v-loading="loading"
    class="app-container train-video-container"
    element-loading-text="拼命加载中"
    element-loading-spinner="el-icon-loading"
  >
    <el-row :gutter="40">
      <el-col :span="24">
        <el-form :inline="true" class="demo-form-inline">
          <el-form-item label="视频关键词">
            <el-input v-model="condition.keyword" placeholder="请输入视频关键词" clearable @clear="refresh" />
          </el-form-item>

          <el-form-item>
            <el-button type="primary" @click="refresh">查询</el-button>
            <el-button @click="refresh">刷新</el-button>
          </el-form-item>
        </el-form>
      </el-col>

      <el-col :span="24">
        <div class="header-container">
          <el-button
            class="header-container__item"
            icon="el-icon-upload"
            type="primary"
            @click="showUploadForm"
          >上传视频</el-button>
          <el-button class="header-container__item" @click="showUploadingOverview">查看上传队列</el-button>
          <el-button v-if="isCheckbox" class="header-container__item" :disabled="selected.length <= 0" :type="selected.length <= 0 ? '': 'primary'" @click="deleteSelectedVideo">删除</el-button>
          <el-button v-if="isCheckbox" class="header-container__item" @click="selectAllVideo">全选</el-button>
          <el-button v-if="isCheckbox" class="header-container__item" @click="cancelOpt">取消</el-button>
          <el-button v-if="!isCheckbox" class="header-container__item" @click="videoManagement">管理</el-button>
        </div>
      </el-col>
    </el-row>

    <div>
      <div v-if="videoListFormatted.length > 0">
        <div class="train-video-list-container">
          <div v-for="(row, rowIndex) in videoListFormatted" :key="rowIndex" class="train-video-list">
            <div class="train-video-list-item-top">
              <el-checkbox v-if="isCheckbox" v-model="row.checked" class="train-video-list-checkbox" :disabled="!!row.user_all > 0" @change="checkup" />
              <video :src="row.path" @click="openPlayer(row)" />
              <span>{{ formatSeconds(row.duration) }}</span>
            </div>
            <div class="train-video-list-item-bootom">
              <div class="item-bootom-title">
                <span class="videoName">{{ setVideoName(row.name) }}</span>
                <span class="videoCount">最少观看:{{ row.mini_num }}次</span>
              </div>
              <div class="item-bootom-notes">
                <span>{{ row.user?.username ?? "这个用户很神秘" }}</span>
                <span>{{ setBIHTime(row.created_at) }}</span>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div v-else>
        <el-empty description="暂无视频" />
      </div>
    </div>

    <el-row v-if="videoListFormatted.length > 0" :gutter="40">
      <el-col :span="24">
        <el-pagination
          class="block"
          layout="total, sizes, prev, pager, next, jumper"
          :current-page="paging.current"
          :page-sizes="[10, 50, 100]"
          :page-size="paging.size"
          :total="paging.total"
          :disabled="isLoading"
          @size-change="handlePageSizeChange"
          @current-change="handlePageChange"
        />
      </el-col>
    </el-row>

    <el-dialog
      width="35%"
      :title="videoPlayer.title"
      :close-on-click-modal="false"
      :visible.sync="videoPlayer.visible"
      :before-close="handlePlayerDialogClose"
      :destroy-on-close="true"
    >
      <video
        ref="video-player"
        style="max-height: 65vh"
        controls
        class="video"
        :src="videoPlayer.path"
        preload="none"
      />
    </el-dialog>

    <el-dialog
      width="35%"
      title="上传队列"
      :close-on-click-modal="false"
      :visible.sync="uploadingOverview.visible"
    >
      <div class="task-list">
        <template v-if="train.videoUploadTasks.length > 0">
          <div
            v-for="item in train.videoUploadTasks"
            :key="item.taskID"
            class="task-item"
            :class="buildTaskClasses(item.state)"
          >
            <video :src="item.localURL" class="cover" />
            <div class="info">
              <div style="padding-bottom: 10px">{{ item.name }}</div>
              <el-progress :status="buildProgressState(item.state)" :percentage="item.progress" />
            </div>

            <div class="tag">
              <el-tag size="mini" type="success">上传完成</el-tag>
            </div>
          </div>
        </template>
        <el-empty v-else description="暂无任务" />
      </div>

      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="closeUploadingOverview">确 定</el-button>
      </div>
    </el-dialog>

    <el-dialog
      width="30%"
      title="上传视频"
      :close-on-click-modal="false"
      :visible.sync="uploadForm.visible"
    >
      <el-form ref="form" :rules="uploadForm.formRules" :model="uploadForm.form" label-width="80px" label-position="top">
        <el-form-item label="视频名称" prop="name">
          <el-input v-model="uploadForm.form.name" placeholder="请输入视频名称" />
        </el-form-item>

        <el-form-item label="每人最少观看次数" prop="minViews">
          <el-input type="number" :value="uploadForm.form.minViews" placeholder="请输入每人最少观看次数" @input="viewsInput" />
        </el-form-item>

        <el-form-item label="选择视频" prop="file">
          <div v-if="uploadForm.form.file" class="video-item">
            <svg-icon icon-class="video" class="icon" />
            <div class="file-name">{{ uploadForm.form.file.name }}</div>
            <i class="el-icon-delete delete-action" @click="uploadForm.form.file = null" />
          </div>

          <div v-else class="video-list__row__upload" @click="openVideoSelector">
            <svg-icon icon-class="upload" class="icon" />
            <div class="tips">上传视频</div>
          </div>
        </el-form-item>
      </el-form>

      <div slot="footer" class="dialog-footer">
        <el-button plain @click="closeUploadForm">取消</el-button>
        <el-button type="primary" @click="createUploadTask">上传</el-button>
      </div>
    </el-dialog>

    <!-- 文件选择 -->
    <input ref="fileSelector" type="file" style="display: none" accept="video/*" @change="onFileSelectorChange">
  </div>
</template>
<style lang="scss" scoped>
.train-video-container {
  min-height: calc(100vh - 84px);
  box-sizing: border-box;
  background-color: #fff;
  margin: 20px;

  .el-pagination {
    padding: 16px 0;

    .btn-prev,
    .btn-next {
      margin: 0;
      margin-right: 6px;
    }
  }

  .header-container {
    padding-bottom: 20px;

    &__item {
      margin-right: 10px;
    }
  }

  .video {
    width: 100%;
  }

  .video-item {
    display: flex;
    flex-wrap: nowrap;
    background-color: #f0f0f0;
    padding: 10px;
    border-radius: 10px;
    align-items: center;

    >.icon {
      font-size: 38px;
    }

    >.file-name {
      padding: 0 10px;
      flex: 1;
      line-height: 16px;
    }

    >.delete-action {
      color: red;
      font-size: 20px;
      cursor: pointer;
    }
  }

  .task-list {
    max-height: 45vh;
    overflow: hidden;
    overflow-y: auto;

    >.task-item {
      margin-top: 10px;
      border-radius: 8px;
      border: 1px solid rgba(0, 0, 0, 0.25);
      padding: 10px;
      display: flex;
      flex-wrap: nowrap;
      position: relative;

      &--failed {
        border-color: red;
      }

      &--success {
        border-color: #13ce66;
      }

      >.cover {
        height: 80px;
        width: 80px;
      }

      >.info {
        flex: 1;
        padding-left: 10px;
        display: flex;
        flex-direction: column;
        flex-wrap: nowrap;
        justify-content: center;
      }

      .tag {
        position: absolute;
        top: 3px;
        right: 3px;
      }
    }
  }

  .video-list {
    &__row {
      display: flex;
      flex-wrap: nowrap;

      &__upload {
        border: 1px dashed rgba(0, 0, 0, 0.2);
        border-radius: 12px;
        cursor: pointer;
        display: flex;
        flex-direction: column;
        flex-wrap: nowrap;
        justify-content: center;
        align-items: center;
        color: #606266;
        > .icon {
          font-size: 68px;
        }
        > .tips {
          text-align: center;
          font-size: 14px;
        }
      }

      &__item {
        min-height: 160px;
        background-color: white;
        border-radius: 12px;
        box-shadow: 0 0 10px 1px rgba(0, 0, 0, 0.1);
        overflow: hidden;
        transition: 0.3s;
        position: relative;

        &:hover {
          transform: scale(1.1);
          cursor: pointer;
        }

        &__cover {
          // width: 100%;
          // height: 180px;
          width: auto;
          height: 160px;
          position: relative;

          .info {
            width: 100%;
            position: absolute;
            bottom: 0;
            left: 0;
            display: flex;
            flex-direction: row-reverse;
            padding: 4px;
            font-weight: bold;
            color: white;
            font-size: 14px;
            background-image: linear-gradient(
              180deg,
              rgba(0, 0, 0, 0) 0%,
              rgba(0, 0, 0, 0.5) 100%
            );
          }
        }

        .body {
          padding: 10px 6px;
          color: #333;
        }

        .stateful {
          width: 100%;
          height: 100%;
          position: absolute;
          top: 0;
          left: 0;
          background-color: rgba(0, 0, 0, 0.5);
          color: white;
          display: flex;
          justify-content: center;
          align-items: center;
          flex-wrap: nowrap;
          flex-direction: column;
          font-size: 14px;

          .icon {
            font-size: 38px;
          }

          &--failed {
            color: red;
            border: 1px dashed red;
          }
        }
      }
    }
  }

  .train-video-list-container {
    display: flex;
    flex-wrap: wrap;

    .train-video-list {
      display: flex;
      flex-wrap: wrap;
      flex-direction: column;
      margin-right: 10px;
      flex-basis: calc(20% - 10px);
      min-height: 160px;

      .train-video-list-item-top {
        position: relative;
        border-radius: 10px;
        cursor:pointer;

        .el-checkbox {
          position: absolute;
          top: 8px;
          left: 10px;
        }

        video {
          border-radius: 10px;
          height: 160px;
          width: 100%;
          object-fit: cover;
        }

        span {
          position: absolute;
          right: 10px;
          bottom: 8px;
          font-weight: bolder;
          color: white;
        }
      }

      .train-video-list-item-bootom {
        display: flex;
        flex-direction: column;
        margin: 10px 0;

        .item-bootom-title {
          .videoName{
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            word-wrap: break-word;
            font-weight: 500;
            font-size: 14px;
            margin-right: 10px;
          }
          .videoCount{
            font-size: 14px;
          }
        }

        .item-bootom-notes {
          color: #8e8e8e;
          font-size: 12px;
          margin-top: 10px;

          span {
            margin-right: 10px;
          }
        }
      }
    }
  }
  .block{
    display: flex;
    justify-content: center;
  }

}
</style>
